﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sherwood.SignOn.Server;
using Sherwood.SignOn.Server.Models;
using Sherwood.SignOn.Server.Models.ViewModels;
using Sherwood.SignOn.Server.Controllers;
using System.Web.Mvc;
using Sherwood.SignOn.Server.Models.Repositories;
using Sherwood.SignOn.Server.Models.Services;

namespace Sherwood.SignOn.Server.Tests
{
    [TestClass]
    public class SignInAndSignOutTests : TestBase
    {
        [TestMethod]
        public void XMlTest()
        {
            getUserProfileResponse profile = new getUserProfileResponse();
            profile.userAccountId = "{userAccountId}";
            profile.username = "{userName}";
            profile.firstName = "{firstName}";
            profile.lastName = "{lastName}";
            profile.email = "{email}";
            profile.dateOfBirth = new DateTime(1950,1,1);
            profile.culture = new List<culture> {new culture {name = ".NetCultureName", priority = 0}};
            profile.country = "{Iso2Country}";
            profile.gender = 0;

        }

        [TestMethod]
        public void SignIn_No_Session_Wrong_Username()
        {
            //Assemble

            IUserAccount user = TestHelper.CreateVerifiedDummyUser("username", "password");

            //Act
            SignInViewModel viewModel = new SignInViewModel();
            viewModel.UserName = "username1";
            viewModel.Password = "password";
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ticket={signoutticket}&signature={signoutsignature}";

            SignInController controller = new SignInController();
            ActionResult result = controller.Index(viewModel) as ActionResult;

            //Assert
            Assert.IsNotNull(result);
            Assert.IsTrue(TestHelper.HasError(controller.ModelState), "There should be an error due to wrong username.");

        }


        [TestMethod]
        public void SignIn_No_Session_Wrong_Password()
        {
            //Assemble

            IUserAccount user = TestHelper.CreateVerifiedDummyUser("username", "password");

            //Act
            SignInViewModel viewModel = new SignInViewModel();
            viewModel.UserName = "username";
            viewModel.Password = "password1";
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ticket={signoutticket}&signature={signoutsignature}";

            SignInController controller = new SignInController();
            ActionResult result = controller.Index(viewModel) as ActionResult;

            //Assert
            Assert.IsNotNull(result);
            Assert.IsTrue(TestHelper.HasError(controller.ModelState), "There should be an error due to wrong username.");

        }


        [TestMethod]
        public void SignIn_No_Session_Valid_Login()
        {
            //Assemble

            IUserAccount user = TestHelper.CreateVerifiedDummyUser("username", "password");

            //Act
            SignInViewModel viewModel = new SignInViewModel();
            viewModel.UserName = "username";
            viewModel.Password = "password";
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";

            SignInController controller = new SignInController();
            RedirectResult result = controller.Index(viewModel) as RedirectResult;
            //int sessionCount = Data.UserSessions.All.Count();
            IUserSession session = UserSessionHelper.GetCurrentUserSession();

            //Assert
            Assert.IsNotNull(result);
            Assert.IsFalse(TestHelper.HasError(controller.ModelState), "There should be no errors.");
            Assert.IsTrue(result.Url.Contains("somewhere.sherwood.codeplex.com/SignIn"), "User should be redirected to return url");
            Assert.IsFalse(result.Url.Contains("signinticket"), "Sign in ticket should be replaced by an actual ticket value");
            Assert.IsFalse(result.Url.Contains("signinsignature"), "Sign in signature should be replaced by a signature value");
            //Assert.IsTrue(sessionCount == 1, "A single new session should have been created.");
            Assert.IsNotNull(session);
            Assert.IsTrue(session.ClientRecords.Count() > 0 && session.ClientRecords.ElementAt(0).SignOutUrl.Equals(viewModel.SignOutUrl), "Sign out url should be recorded.");

        }



        [TestMethod]
        public void SignIn_Existing_Session_No_Login()
        {
            //Assemble

            IUserAccount user = TestHelper.CreateVerifiedDummyUser("username", "password");
            //Create session and simulate sign in
            SignInViewModel viewModel = new SignInViewModel();
            viewModel.UserName = "username";
            viewModel.Password = "password";
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            SignInController controller = new SignInController();
            RedirectResult result = controller.Index(viewModel) as RedirectResult;
            user = Data.UserAccounts.GetUserAccountByUsername("username"); //reload user


            //Act (simulate login request from another domain without username and password)
            viewModel = new SignInViewModel();
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhereelse.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewherelse.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            controller = new SignInController();
            result = controller.Index(viewModel) as RedirectResult;
            user = Data.UserAccounts.GetUserAccountByUsername("username"); //reload user
            //int sessionCount = Data.UserSessions.All.Count();
            //IUserSession session = Data.UserSessions.All.FirstOrDefault();
            IUserSession session = UserSessionHelper.GetCurrentUserSession();

            //Assert
            Assert.IsNotNull(result);
            Assert.IsTrue(result.Url.Contains("somewhereelse.sherwood.codeplex.com/SignIn"), "User should be redirected to return url");
            Assert.IsFalse(result.Url.Contains("signinticket"), "Sign in ticket should be replaced by an actual ticket value");
            Assert.IsFalse(result.Url.Contains("signinsignature"), "Sign in signature should be replaced by a signature value");
            //Assert.IsTrue(sessionCount == 1, "There should still only be one session.");
            Assert.IsNotNull(session);
            Assert.IsTrue(session.ClientRecords.Count() == 2, "There should now be two client records.");
            Assert.IsTrue(session.ClientRecords.ElementAt(1).SignOutUrl.Equals(viewModel.SignOutUrl), "Sign out url should be recorded.");

        }


        [TestMethod]
        public void SignIn_SignOut_Test()
        {
            //Assemble

            IUserAccount user = TestHelper.CreateVerifiedDummyUser("username", "password");
            //Signin
            SignInViewModel viewModel = new SignInViewModel();
            viewModel.UserName = "username";
            viewModel.Password = "password";
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            SignInController controller = new SignInController();
            RedirectResult result = controller.Index(viewModel) as RedirectResult;


            //Act (SignOut)
            viewModel = new SignInViewModel();
            viewModel.ClientSessionId = Guid.NewGuid().ToString(); //new session id from client...
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            SignOutController signOutController = new SignOutController();
            result = signOutController.Index(viewModel) as RedirectResult;
            //int sessionCount = Data.UserSessions.All.Count();
            //IUserSession session = Data.UserSessions.All.FirstOrDefault();
            IUserSession session = UserSessionHelper.GetCurrentUserSession();

            //Assert
            Assert.IsNotNull(result);
            Assert.IsFalse(TestHelper.HasError(signOutController.ModelState), "There should not be any errors.");
            Assert.IsTrue(result.Url.Contains("~/SignIn"), "User should be redirected to login page");
            //Assert.IsTrue(sessionCount == 0, "There should not be any sessions after a signout.");
            Assert.IsNull(session);

        }



        [TestMethod]
        public void SignIn_SignOut_SignIn_Test()
        {
            //Assemble

            IUserAccount user = TestHelper.CreateVerifiedDummyUser("username", "password");
            //Signin
            SignInViewModel viewModel = new SignInViewModel();
            viewModel.UserName = "username";
            viewModel.Password = "password";
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            SignInController controller = new SignInController();
            RedirectResult result = controller.Index(viewModel) as RedirectResult;


            //Act (SignOut)
            viewModel = new SignInViewModel();
            viewModel.ClientSessionId = Guid.NewGuid().ToString(); //new session id from client...
            viewModel.ReturnUrl = "http://somewhere.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewhere.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            SignOutController signOutController = new SignOutController();
            result = signOutController.Index(viewModel) as RedirectResult;
            //int sessionCount = Data.UserSessions.All.Count();
            //IUserSession session = Data.UserSessions.All.FirstOrDefault();
            IUserSession session = UserSessionHelper.GetCurrentUserSession();
            
            //Sign in again (another domain without username and password)
            viewModel = new SignInViewModel();
            viewModel.ClientSessionId = Guid.NewGuid().ToString();
            viewModel.ReturnUrl = "http://somewhereelse.sherwood.codeplex.com/SignIn/?ReturnUrl=bogus&ticket={signinticket}&signature={signinsignature}";
            viewModel.SignOutUrl = "http://somewherelse.sherwood.codeplex.com/SignOut/?ticket={signoutticket}&signature={signoutsignature}";
            controller = new SignInController();
            ViewResult result1 = controller.Index(viewModel) as ViewResult;
            //sessionCount = Data.UserSessions.All.Count();
            session = UserSessionHelper.GetCurrentUserSession();


            //Assert
            Assert.IsNotNull(result1); //login page should redirect back to itself (no username or password provided and no existing session)
            Assert.IsFalse(TestHelper.HasError(controller.ModelState), "There should not be any errors -- username and password are blank.");
            //Assert.IsTrue(sessionCount == 0, "There should not be any session because username/password have not been provided");
            Assert.IsNull(session);

        }



    }
}
